
//--Yangxin--

`include "defines.v"

module if_stage(
	input  wire           				clk  		   ,
	input  wire           				reset		   ,
	//allowin
	input  wire           				ds_allowin	   ,
	//brbus
	input  wire [      `BR_BUS_WD -1:0] br_bus         ,    // To do
	//to ds
	output wire    		  				fs_to_ds_valid ,
	output wire [`FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus   ,
	//input  wire [				63:  0] inst_addr      ,

	//inst sram inteface
	output wire        					inst_sram_en   ,
	output wire [				   7:0] inst_sram_wen  ,
	output wire [				  63:0] inst_sram_addr ,
	output wire [	 			  63:0] inst_sram_wdata,
	input  wire [				  31:0] inst_sram_rdata,

	//exception
	input  wire                         except_flush   ,
	input  wire [				  63:0]	except_new_pc   
	);

reg		fs_valid;
wire    fs_ready_go;
wire    fs_allowin;
wire    to_fs_valid;

wire [63:0] seq_pc;
wire [63:0] next_pc;

wire        br_taken;
wire [63:0] br_target;
reg         br_taken_d1;
reg  [63:0] br_target_d1;
reg         br_taken_d2;
reg  [63:0] br_target_d2;

always @(posedge clk) begin
	br_target_d1 <= br_target;
	br_taken_d1 <= br_taken;
	br_target_d2 <= br_target_d1;
	br_taken_d2 <= br_taken_d1;
end

wire   pre_fs_ready_go;
wire   br_stall;

assign  {br_stall,br_taken,br_target} = br_bus;

wire [31:0] fs_inst;
reg  [63:0] fs_pc;
assign fs_to_ds_bus = {fs_inst, //95:64
					   fs_pc    //63:0
					   };

//pre-IF stage

assign pre_fs_ready_go = ~br_stall;
//assign to_fs_valid = ~reset && pre_fs_ready_go;
assign to_fs_valid = ~reset;
assign seq_pc = fs_pc + 64'h4;
assign next_pc = br_taken ? br_target : seq_pc;
//assign next_pc = br_taken_d1 ? br_target_d1 : seq_pc;
//assign next_pc = br_taken_d2 ? br_target_d2 : seq_pc;
parameter PC_START_RESET = `PC_START - 4;


//IF stage
assign fs_ready_go = ~br_taken;
//assign fs_allowin = !fs_valid || fs_ready_go && ds_allowin;
assign fs_allowin = !fs_valid || ds_allowin;
assign fs_to_ds_valid = fs_valid && fs_ready_go;
always @(posedge clk) begin
	if (reset) begin
		// reset
		fs_valid <= 1'b0;
	end
	else if (fs_allowin) begin
		fs_valid <= to_fs_valid;
	end

	if(reset) begin
		fs_pc <= PC_START_RESET;
	end
	else if(except_flush) begin
		fs_pc <= except_new_pc ;
	end
	else if(to_fs_valid && fs_allowin) begin
		fs_pc <= next_pc;
	end
end

//assign inst_sram_en = to_fs_valid && fs_allowin && ~br_stall;
assign inst_sram_en = to_fs_valid && fs_allowin;
assign inst_sram_wen = 8'h0;
assign inst_sram_addr = next_pc;
assign inst_sram_wdata = 64'h0;

assign fs_inst = inst_sram_rdata;

//Access memory
wire [63:0] pc;
assign pc = fs_pc;
reg [63:0] rdata;
RAMHelper RAMHelper(
  .clk              (clk),
  .en               (1),
  .rIdx             ((pc - `PC_START) >> 3),
  .rdata            (rdata),
  .wIdx             (0),
  .wdata            (0),
  .wmask            (0),
  .wen              (0)
);
wire [31:0] inst;
assign inst = pc[2] ? rdata[63 : 32] : rdata[31 : 0];

assign fs_inst = inst;

endmodule
